#ifndef STRINGUTIL_CPP
#define STRINGUTIL_CPP

#include "stringutil.h"
#include <iostream>
#include <string>

/////////////////////////
//I NEED TO MAKE SURE THESE WORK ALL CORRECTLY
//MULTI-LENGTHED STRINGS ON ALL OF THEM

char			str_empty	[1];

///////////////////////////////////////
 // String Compare (case insensitive) //
 ///////////////////////////////////////
/* int strcasecmp (const char *str1, const char *str2) {
 	for (; ((tolower(*str1) - tolower(*str2)) == 0); ++str1, ++str2) {
		if (*str1 == '\0' || *str2 == '\0')
		return 0;
	}

 	return (tolower(*str1) - tolower(*str2));
 }*/
 
/* int strncasecmp (const char *str1, const char *str2, unsigned int len) {
 	for (; ((tolower(*str1) - tolower(*str2)) == 0); ++str1, ++str2) {
 		if (*str1 == '\0' || *str2 == '\0')
			return 0;
 
 		if (--len == 0) break;
 	}
 
 	return (tolower(*str1) - tolower(*str2));
}*/

///// These functions handle string comparing. They're all case
///// insensitive. 
///////////////////////////////////////////////////////////////
bool str_cmp( std::string string1, std::string string2 ) {
	std::string::iterator cChar, cChar2;	

    if ( string1.empty() )
	    return false;

    if ( string2.empty() )
		return false;

	for ( cChar = string1.begin(), cChar2 = string2.begin(); cChar != string1.end() || cChar2 != string2.end(); cChar++, cChar2++ ) {
		if ( LOWER( (*cChar) ) != LOWER( (*cChar2) ) )
			return false;
	}

	return true;
}

bool str_cmp( std::string &string1, char * string2 ) {
	std::string::iterator cChar;

	if ( string1.empty() )
		return false;

	if ( string2 == NULL )
		return false;

	for ( cChar = string1.begin(); cChar != string1.end() || *string2; ++cChar, string2++ ) {
		if ( LOWER( (*cChar) ) != LOWER( *string2 ) )
			return false;
	}

	return true;
}

bool str_cmp( char * string1, std::string &string2 ) {
	std::string::iterator cChar;

	if ( string1 == NULL )
		return false;

	if ( string2.empty() )
		return false;

	for ( cChar = string2.begin(); cChar != string2.end() || *string1; ++cChar, string1++ ) {
		if ( LOWER( (*string1) ) != LOWER( *cChar ) )
			return false;
	}

	return true;
}

bool str_cmp( char * string1, char * string2 ) {
	if ( string1 == NULL )
	   return false;

    if ( string2 == NULL )
	   return false;

    for ( ; *string1 || *string2; string1++, string2++ ) {
	   if ( LOWER(*string1) != LOWER(*string2) )
	      return false;
    }

    return true;
}

/// end str_cmp

///// These functions handle comparing the beginning of strings
///// (Prefix Matching) They're all case insensitive. 
///////////////////////////////////////////////////////////////
bool str_prefix( std::string &string1, std::string &string2 ) {
	std::string::iterator cChar, cChar2;

    if ( string1.empty() )
	   return false;

    if ( string2.empty() )
	   return false;

    for ( cChar = string1.begin(), cChar2 = string2.begin(); cChar != string1.end(); cChar++, cChar2++ ) {
		if ( LOWER( (*cChar) ) != LOWER( (*cChar2) ) )
			return false;
	}

    return true;
}

bool str_prefix( std::string &string1, char * string2 ) {
	std::string::iterator cChar;

	if ( string1.empty() )
		return false;

	if ( string2 == NULL )
		return false;

	for ( cChar = string1.begin(); cChar != string1.end(); ++cChar, string2++ ) {
		if ( LOWER( (*cChar) ) != LOWER( *string2 ) )
			return false;
	}

	return true;
}

bool str_prefix( char * string1, std::string &string2 ) {
	std::string::iterator cChar;

	if ( string1 == NULL ) 
		return false;

	if ( string2.empty() ) 
		return false;
	for ( cChar = string2.begin(); *string1; ++cChar, string1++ ) {
		if ( LOWER( (*string1) ) != LOWER( *cChar ) )
			return false;
	}

	return true;
}

bool str_prefix( char * string1, char * string2 ) {
	if ( string1 == NULL )
	   return false;

    if ( string2 == NULL )
	   return false;
 

    for ( ; *string1; string1++, string2++ ) {
	   if ( LOWER(*string1) != LOWER(*string2) )
	      return false;
    }

    return true;
}


//// lowerString :: This is a function to convert a string to lowerCase without altering the original
////////////////////////////////////////////
char * lowerString( const char * string1 ) {
    char * str_new;

	str_new = new char[ strlen( string1 ) + 1];	

	for ( unsigned int i = 0; i < ( strlen( string1 ) + 1 ); i++ ) {
	   str_new[i] = LOWER( string1[i] );
    } 
	
	return str_new;
}

//// upperString :: This is a function to convert a string to upperCase without altering the original
////////////////////////////////////////////
char * upperString( const char * string1 ) {
    char * str_new;

	str_new = new char[ strlen( string1 ) + 1];	

	for ( unsigned int i = 0; i < ( strlen( string1 ) + 1 ); i++ ) {
	   str_new[i] = UPPER( string1[i] );
    } 
	
	return str_new;
}

///// Similar to strstr, yet is case insensitive 
///////////////////////////////////////////////////////////////
bool str_str( char * string1, char * string2 ) {
    if ( string1 == NULL ) 
	   return false;

    if ( string2 == NULL )
	   return false;


    if ( strstr( lowerString( string1 ), lowerString( string2 ) ) == NULL )
		return false;
   

    return true;
}

bool str_str( std::string string1, std::string string2 ) {
    if ( string1.empty() ) 
	   return false;

    if ( string2.empty() )
	   return false;


    if ( strstr( lowerString( string1.c_str() ), lowerString( string2.c_str() ) ) == NULL )
		return false;
   

    return true;
}



//// str_dup :: Allocates memory for a pointer and puts a string in it
////////////////////////////////////////////
char * str_dup( const char *str ) {
    char * str_new;

    if ( str[0] == '\0' )
	return &str_empty[0];

    str_new = new char[ strlen(str) + 1 ];
    strcpy( str_new, str );
    return str_new;
}

//// free_string :: Frees the memory in a pointer. ( usually goes along with str_dup )
////////////////////////////////////////////
void free_string( char *pstring ) {
    if ( pstring == NULL || pstring == &str_empty[0] )
	return;

    delete pstring;
    return;
}

///// Tonk stuff /////
void rtrim( std::string& dest, const std::string& target ) {
	std::string foobar = target;
	if ( foobar.size() == 0 )
		return;
	while ( foobar[foobar.size()-1] == ' ' ||
			foobar[foobar.size()-1] == '\n' ||
			foobar[foobar.size()-1] == '\r' ||
			foobar[foobar.size()-1] == '\t' )
		foobar.resize( foobar.size() - 1 );
	dest = foobar;
	return;
}

void rtrim( std::string& dest, std::string& target ) {
	std::string foobar = target;
	if ( foobar.size() == 0 )
		return;
	while ( foobar[foobar.size()-1] == ' ' ||
			foobar[foobar.size()-1] == '\n' ||
			foobar[foobar.size()-1] == '\r' ||
			foobar[foobar.size()-1] == '\t' )
		foobar.resize( foobar.size() - 1 );
	dest = foobar;
	return;
}

void ltrim( std::string& dest, const std::string& target ) {
	std::string foobar = target;
	if ( foobar.size() == 0 )
		return;
	while ( foobar[0] == ' ' ||
			foobar[0] == '\n' ||
			foobar[0] == '\r' ||
			foobar[0] == '\t' ) {
		for ( int x=0; x < (int)foobar.size() - 1; x++ )
			foobar[x] = foobar[x+1];
		foobar.resize( foobar.size() - 1 );
	}
	dest = foobar;
	return;
}

void ltrim( std::string& dest, std::string& target ) {
	std::string foobar = target;
	if ( foobar.size() == 0 )
		return;
	while ( foobar[0] == ' ' ||
			foobar[0] == '\n' ||
			foobar[0] == '\r' ||
			foobar[0] == '\t' ) {
		for ( int x=0; x < (int)foobar.size() - 1; x++ )
			foobar[x] = foobar[x+1];
		foobar.resize( foobar.size() - 1 );
	}
	dest = foobar;
	return;
}

void loginTrim( std::string& dest, std::string& target ) {
	std::string foobar = target;
	if ( foobar.size() == 0 )
		return;
	while ( foobar[0] == ' ' ||
			foobar[0] == '\n' ||
			foobar[0] == '\r' ||
			foobar[0] == '\t' ||
			!isalpha( foobar[0] ) )
		for ( int x=0; x < (int)foobar.size(); x++ )
			foobar[x] = foobar[x+1];
	dest = foobar;
	return;
}

void trim( std::string& dest, std::string& target ) {
	ltrim( dest, target );
	rtrim( dest, target );
	return;
}

char* cprint_private( char c ) {
	switch ( c ) {
		// colors
		case 'r': return "\033[40;31m"; break;		// dark red
		case 'R': return "\033[40;31;1m"; break;	// bright red
		case 'g': return "\033[40;32m"; break;		// dark green
		case 'G': return "\033[40;32;1m"; break;	// bright green
		case 'y': return "\033[40;33m"; break;		// dark yellow or brown
		case 'Y': return "\033[40;33;1m"; break;	// bright yellow
		case 'b': return "\033[40;34m"; break;		// dark blue
		case 'B': return "\033[40;34;1m"; break;	// bright blue
		case 'm': return "\033[40;35m"; break;		// dark magenta
		case 'M': return "\033[40;35;1m"; break;	// bright magenta
		case 'c': return "\033[40;36m"; break;		// dark cyan
		case 'C': return "\033[40;36;1m"; break;	// bright cyan
		case 'W': return "\033[40;37;1m"; break;	// pure white
		case 'w': return "\033[1;30m"; break;		// dark gray or black
		case '{': return "{"; break;				// a plain brace
		default: return "\033[0;0;0m"; break;		// default gray
	}
}

char* cprint_private( char c, char d ) {
	if ( c == '!' ) { // Underline
		switch ( d ) {
			case 'R': return "\033[31;4m\033[1m"; break;	// bright red
			case 'r': return "\033[31;4m"; break;			// dark red
			case 'G': return "\033[32;4m\033[1m"; break;	// bright green
			case 'g': return "\033[32;4m"; break;			// dark green
			case 'Y': return "\033[33;4m\033[1m"; break;	// bright yellow
			case 'y': return "\033[33;4m"; break;			// dark yellow
			case 'B': return "\033[34;4m\033[1m"; break;	// bright blue
			case 'b': return "\033[34;4m"; break;			// dark blue
			case 'M': return "\033[35;4m\033[1m"; break;	// bright magenta
			case 'm': return "\033[35;4m"; break;			// dark magenta
			case 'C': return "\033[36;4m\033[1m"; break;	// bright cyan
			case 'c': return "\033[36;4m"; break;			// dark cyan
			case 'W': return "\033[37;4m\033[1m"; break;	// bright white
			case 'w': return "\033[37;4m"; break;			// dark gray or black
			default: return "\033[0;0;0m"; break;			// default
		}
	}
	if ( c == '@' ) { // Highlight
		switch ( d ) {
			case 'R': case 'r': return "\033[40;31;7m"; break;	// red
			case 'G': case 'g': return "\033[40;32;7m"; break;	// green
			case 'Y': case 'y': return "\033[40;33;7m"; break;	// yellow
			case 'B': case 'b': return "\033[40;34;7m"; break;	// blue
			case 'M': case 'm': return "\033[40;35;7m"; break;	// magenta
			case 'C': case 'c': return "\033[40;36;7m"; break;	// cyan
			case 'W': case 'w': return "\033[40;37;7m"; break;	// gray
			default: return "\033[0;0;0m"; break;				// default
		}
	}

	return "\033[0;0m";
}

bool same( std::string& one, std::string& two )
{
	if ( one == two )
		return true;
	else
		return false;
}

bool same( char* one, char* two )
{
	if ( strcmp( one, two ) == 0 )
		return true;
	else
		return false;
}

void init( char* it )
{
	for ( int x=0; x < (int)strlen(it); x++ )
		it[x] = '\0';
	return;
}

std::string& spaces( int space, const char* message, std::string& temp ) {
	temp.clear();
	for ( int i = (int)strlen(message); i < space; i++ )
		temp << ' ';
	return temp;
}

std::string& spaces( int space, int number, std::string& temp ) {
	std::string message;
	message << number;
	temp.clear();
	for ( int i = message.size(); i < space; i++ )
		temp << ' ';
	return temp;
}

std::string& format( int space, const char* message, std::string& temp, char color ) {
	temp.clear();
	temp << '{' << color << message;
	for ( int i = (int)strlen(message); i < space; i++ )
		temp << ' ';
	temp << "{x";
	return temp;
}

std::string& format( int space, char* message, std::string& temp, char color ) {
	temp.clear();
	temp << '{' << color << message;
	for ( int i = (int)strlen(message); i < space; i++ )
		temp << ' ';
	temp << "{x";
	return temp;
}

std::string& format( int space, std::string message, std::string& temp, char color ) {
	temp.clear();
	temp << '{' << color << message;
	for ( int i = message.length(); i < space; i++ )
		temp << ' ';
	temp << "{x";
	return temp;
}

std::string& format( int space, int number, std::string& temp, char color ) {
	temp.clear();
	std::string message;
	message.clear();
	message << number;
	temp << '{' << color << message;
	for ( int i = message.length(); i < space; i++ )
		temp << ' ';
	temp << "{x";
	return temp;
}

std::string& sFormat( int space, std::string message, std::string& temp, std::string color ) {
	temp.clear();
	temp << '{' << color << message;
	for ( int i = message.length(); i < space; i++ )
		temp << ' ';
	temp << "{x";
	return temp;
}

bool sub_str( std::string sub_string, std::string str_string ) { // CLEAN ME UP
	// This function is still a little sloppy...
	bool there = false;
	char* sub = new char[strlen(sub_string.c_str())]; // Looking for this substring
	strcpy( sub, lowerString( sub_string.c_str() ) );
	char* str = new char[strlen(str_string.c_str())]; // Target string to search through
	strcpy( str, lowerString( str_string.c_str() ) );

	for ( int i=0; i < (int)strlen( str ); i++ ) {
		if ( str[i] == sub[0] ) {
			for ( int j=0; j < (int)strlen( sub ); j++ ) {
				if ( LOWER( str[i+j] ) == LOWER( sub[j] ) ) {
					there = true;
					continue;
				} else {
					there = false;
					break;
				}
			}
		}
		if ( there )
			return true;
	}

	return false;
}

#endif // #ifndef STRINGUTIL_CPP
